package com.hwtx.form.domain.def.meta;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hwtx.form.domain.FormConstants;
import com.hwtx.form.domain.def.FormConfigExt;
import com.hwtx.form.domain.def.meta.config.SelectComponentConfig;
import com.hwtx.form.domain.vo.FormConfigQueryVo;
import com.hwtx.form.util.FormUtil;
import com.hwtx.form.util.JacksonUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.hwtx.form.domain.FormConstants.FormComponentType.FORM_COM_SINGLE_SELECT;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Column {

    private String name;
    private Boolean sortable;
    private Style style;
    private Boolean hidden;
    private Object value;
    private String label;
    private String fixed;
    private Integer width;
    @JsonIgnore
    private Map<String, Object> ext;

    public static Column buildHiddenColumn(String name, Object value) {
        Column column = new Column();
        column.setHidden(true);
        column.setName(name);
        if (value != null) {
            column.setValue(value);
        }
        return column;
    }

    public static List<Column> buildColumns(List<FormConfigQueryVo> formConfigQueryList, boolean crud) {
        List<Column> columns = Lists.newArrayList();
        formConfigQueryList.stream().filter(formConfigQuery -> Objects.equals(formConfigQuery.getIsListShow(), (byte) 1)).forEach(formConfigQuery -> {
            boolean isSelect = false;
            FormConfigExt.FormConfigCtr formConfigCtr = null;
            if (StringUtils.isNotEmpty(formConfigQuery.getExt())) {
                FormConfigExt formConfigExt = FormUtil.getFormConfigExt(formConfigQuery.getExt());
                if (formConfigExt != null) {
                    formConfigCtr = FormUtil.getFormConfigCtr(FormConstants.LIST, formConfigExt);
                    isSelect = Objects.equals(formConfigQuery.getListController(), FORM_COM_SINGLE_SELECT.getValue());
                }
            }
            CommonColumn column = new CommonColumn();
            if (Objects.equals(formConfigQuery.getIsSort(), (byte) 1)) {
                column.setSortable(true);
            }
            column.setLabel(formConfigQuery.getDescription());
            if (formConfigCtr != null) {
                column.setWidth(formConfigCtr.getWidth());
            }
            column.setName(StringUtils.isNotBlank(formConfigQuery.getName()) ? formConfigQuery.getName() : formConfigQuery.getField());
            if (formConfigQuery.getFormController() != null && FormConstants.FormComponentType.of(formConfigQuery.getFormController())
                    == FormConstants.FormComponentType.FORM_COM_IMAGE) {
                column.setType(Component.Image.TYPE);
                Map<String, Object> map = Maps.newHashMap();
                map.put(Component.Image.EnlargeAble, true);
                map.put(Component.Image.InnerClassName, Component.Image.No_Border);
                column.setExt(map);
            }
            if (isSelect && formConfigCtr != null) {
                SelectComponentConfig.buildColumnInfo(column, formConfigCtr);
            }
            if (crud) {
                Style style = new Style();
                style.addBorderRight();
                column.setStyle(style);
            }
            columns.add(column);
        });
        return columns;
    }

    @JsonAnyGetter  // 将 ext 的键值对展开到顶层
    public Map<String, Object> getExt() {
        return ext;
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class CommonColumn extends Column {
        private String type;
        private List<Component> buttons;
        private Map<String, Object> map;
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class QuickColumn extends Column {
        QuickEdit quickEdit;
    }

    @Data
    @JsonSerialize(using = CustomSerializer.class)
    public static class QuickEdit {
        String mode = "inline";
        Component component;
        boolean saveImmediately = true;
    }

    public static class CustomSerializer extends StdSerializer<QuickEdit> {
        public CustomSerializer() {
            super(QuickEdit.class);
        }

        @Override
        public void serialize(QuickEdit value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeStartObject();
            for (Map.Entry<String, Object> entry : JacksonUtil.object2Map(value.getComponent()).entrySet()) {
                if (entry.getValue() != null) {
                    gen.writeObjectField(entry.getKey(), entry.getValue());
                }
            }
            gen.writeBooleanField("saveImmediately", value.isSaveImmediately());
            gen.writeStringField("mode", value.getMode());
            gen.writeEndObject();
        }
    }
}